import java.util.*;
import sg.edu.nus.comp.cs3243.pipedream.*;

public class HMachine {

	public static final byte WEST = 4, NORTH = 1, EAST = 2, SOUTH = 3, 
		   NODIR = 0, MAXX = 7, MAXY = 7, NOT_FILLED = 0, QUEUESIZE = 5;
	
	public static final int INF = 99999;

	/*
	   Don't modify board as it will modify the map in the Driver/Game
	   Call it realBoard, more accurate?
	*/
	final byte realDestroyable[][];
	final char realBoard[][]; // pointer for storing the board
	final byte realOozeSpot[];
	final int realTimeLeft, realScoreAmount;
	Driver myDriver;

	int maxScore, penalty;
	final char queue[];
	byte maxPosition[] = {-1, -1};

	// recovery for no position found
	int touched[][] = new int[MAXX][MAXY];

	public HMachine(Driver d) 
	{
		// may want to setup Driver instead
		myDriver = d;
		queue = d.getQueue();
		realBoard = d.getBoard();	//set up playing board for this round

		realDestroyable = new byte[MAXX][MAXY];
		for (int x = 0; x < MAXX; x++) {
			for (int y = 0; y < MAXY; y++) {
				realDestroyable[x][y] = 
					(byte) (myDriver.getFill(x, y) == NOT_FILLED ? 0 : 1);
			}
		}
		// starting pipe is INDESTRUCTIBLE
		realDestroyable[3][3] = 2;

		// The following is just to find out realOozeSpot

		byte destroyable[][] = new byte[MAXX][MAXY];
		for(int a = 0; a < MAXX; a++)
			for(int b = 0; b < MAXY; b++)
				destroyable[a][b] = realDestroyable[a][b];

		byte currPosDir[] = {(byte) myDriver.getNextOozeSpotX(), 
			(byte) myDriver.getNextOozeSpotY(), 
			(byte) myDriver.getNextOozeDirection()};
		if (currPosDir[0]<0 || currPosDir[0] >= MAXX || 
			currPosDir[1]<0 || currPosDir[1] >= MAXY) {
			realTimeLeft = myDriver.getTimeToNextOoze();
			realScoreAmount = 0;
		} else {
			int[] ScoreTime = doFlow(realBoard, destroyable, currPosDir);
			realScoreAmount = ScoreTime[0];
			realTimeLeft = myDriver.getTimeToNextOoze() + ScoreTime[1];
		}

		// initialise penalty
		for(int a = 0; a < MAXX; a++)
			for(int b = 0; b < MAXY; b++)
				if (destroyable[a][b] == 0 && realBoard[a][b] != ' ')
					penalty++;

		realOozeSpot = new byte[2];
		realOozeSpot[0] = currPosDir[0];
		realOozeSpot[1] = currPosDir[1];

		// End
	}
	
	/*
	 * This method forces the game to place curves at their 
	 * respective corners given a NOCHOICE situation
	 */
	public int putAtTheCorners()
	{
		if(queue[0]=='c' && realBoard[0][0]==' ')
		{
			maxPosition[0]=0;
			maxPosition[1]=0;
			return INF;
		}	
		if(queue[0]=='z' && realBoard[6][0]==' ')
		{
			maxPosition[0]=6;
			maxPosition[1]=0;
			return INF;
		}	
		if(queue[0]=='e' && realBoard[0][6]==' ')
		{
			maxPosition[0]=0;
			maxPosition[1]=6;
			return INF;
		}
		if(queue[0]=='q' && realBoard[6][6]==' ')
		{
			maxPosition[0]=6;
			maxPosition[1]=6;
			return INF;
		}
		return 0;
	}
	
	public byte[] calculateHeuristics()
	{
		maxScore = realScoreAmount;
		startSearch();

		// Resolve if no favourable solution can be found thus far
		if (maxPosition[0] == -1) {
			// System.out.println("NOCHOICE");
			
			int Mscore= -INF;
			int score;
			
			score = putAtTheCorners();
			
			/* 
			 * if there isn't a possibility of placing curve pieces at the corners,
			 * place it else where using checksides(.....)
			 */
			if( score != INF )
				for(byte x = 0; x < MAXX; x++)
					for(byte y = 0; y < MAXY; y++)
						// try to never destroy
						if(realBoard[x][y] == ' ') {
							
							score = checkSides(x, y, queue[0]) - touched[x][y];
							if (score > Mscore)
							{
								Mscore = score;
								maxPosition[0] = x;
								maxPosition[1] = y;
							}							
						}
		}
		
		return maxPosition;
	}

	/**
	 * getDir finds the new direction after traversing a given piece
	 * for traversing the pipes
	 *
	 * @param currDir The current direction of the flow
	 * @param piece The piece
	 * @return the new direction after going through <code>piece</code>.
	 *
	 */
	private byte getDir(byte currDir, char piece)
	{
		switch(piece) {
			case '|':
				if (currDir == NORTH || currDir == SOUTH) return currDir;
				break;
			case '-':
				if (currDir == WEST || currDir == EAST) return currDir;
				break;
			case 'c':
				if (currDir == WEST) return SOUTH;
				else if (currDir== NORTH) return EAST;
				break;
			case 'z':
				if (currDir == EAST) return SOUTH;
				else if (currDir == NORTH) return WEST;
				break;
			case 'e':
				if (currDir == WEST) return NORTH;
				else if (currDir == SOUTH) return EAST;
				break;
			case 'q':
				if (currDir == EAST) return NORTH;
				else if (currDir == SOUTH) return WEST;
				break;
			case '+':
				return currDir;
			// blank piece or other piece
			default:
				return NODIR;
		}
		return NODIR;
	}

	/**
	 * initialise values to conduct search
	 *
	 */
	void startSearch() {

		char playingboard[][] = new char[MAXX][MAXY];
		byte destroyable[][] = new byte[MAXX][MAXY];

		// initialise destroyable with all real stuff
		for(int a = 0; a < MAXX; a++)
			for(int b = 0; b < MAXY; b++)
				destroyable[a][b] = realDestroyable[a][b];

		// TODO
		// check values of next ooze direction
		byte currPosDir[] = {(byte) myDriver.getNextOozeSpotX(), 
			(byte) myDriver.getNextOozeSpotY(), 
			(byte) myDriver.getNextOozeDirection()};
		if (currPosDir[0]<0 || currPosDir[0] >= MAXX || 
			currPosDir[1]<0 || currPosDir[1] >= MAXY) {
			// Dead end so we do flow ourselves
			currPosDir[0] = 3;
			currPosDir[1] = 2;
			currPosDir[2] = NORTH;
			for(int a = 0; a < MAXX; a++)
				for(int b = 0; b < MAXY; b++)
					destroyable[a][b] = 0;
		}
			
		playingboard = realBoard;

		//first time doFlow is run, its returned score is not used
		// System.out.println("STARTSEARCH");
		
		//WJ: shouldn't the current score be adjusted ever since the start of the game?
		//    not sure if it would make a difference but the average scores did go higher
		int currScoreTime[] = doFlow(playingboard, destroyable, currPosDir, 1);
		currScoreTime[1] = 0;
		
		//int currScore = 0;
		// All queue positions have null positions ; a 5 by 2 array ;
		byte currQueuePos[][] = {{-1, -1},{-1, -1},{-1, -1},{-1, -1},{-1, -1}};

		doSearch(playingboard, destroyable, currQueuePos, currPosDir, currScoreTime);
	}

	/**
	 * writes to maxPosition the best position for the next item in the queue
	 *
	 * @param playingboard the current state of the playing board
	 * @param destroyable whether a piece is NOT filled so that it can be destroyed
	 * @param currQueuePos records the position of the queue pieces for each queue piece
	 * @param currPosDir current position and direction. {x, y, dir}
	 */
	void doSearch (final char playingboard[][], final byte destroyable[][], 
			       final byte currQueuePos[][], final byte currPosDir[], 
				   final int currScoreTime[]) {

		// System.out.println(currScoreTime[0]);

		// If the time required for this configuration is too long, don't bother
		if (currScoreTime[1] > realTimeLeft) return;
			       	
		byte newQueue[][] = new byte[5][2];
		char tempPiece;
		int newScoreTime[] = new int[2];

		byte newPosDir[] = new byte[3];
		newPosDir[0] = currPosDir[0];
		newPosDir[1] = currPosDir[1];
		newPosDir[2] = currPosDir[2];

		byte newDestroyable[][] = new byte[MAXX][MAXY];
		char newBoard[][] = new char[MAXX][MAXY];
		
		// DEEP COPY
		for(int a = 0; a < MAXX; a++)
			for(int b = 0; b < MAXY; b++) {
				newDestroyable[a][b] = destroyable[a][b];
				newBoard[a][b] = playingboard[a][b];
			}

		// record the position of the next piece
		// >= cos make sure we get all the best cases because of later pruning
		if ( currScoreTime[0] >= maxScore && currQueuePos[0][0] != -1 ) {
			// System.out.println(newScoreTime[0]);
			// find out whether this state is even possible 
			int timeNeeded = 0;
			for (int i = 0; i < QUEUESIZE; i++) {
				if (currQueuePos[i][0] != -1)
					timeNeeded = i;
			}
			timeNeeded++;
			timeNeeded += currScoreTime[1];

			if (timeNeeded <= realTimeLeft) {

				// calculate penalty of this state
				int newPenalty = 0;
				for(int a = 0; a < MAXX; a++)
					for(int b = 0; b < MAXY; b++)
						if (destroyable[a][b] == 0 && 
								playingboard[a][b] != ' ')
							newPenalty++;

				if ((currScoreTime[0] == maxScore && 
							newPenalty < penalty) ||
						currScoreTime[0] > maxScore) {

					// to restrict pieces from being randomly placed along positions that
					// will lead to dead ends. Method forces the game to go into a NOCHOICE state
					if(!placeConstraints(playingboard, currQueuePos))
					{
						maxPosition[0] = currQueuePos[0][0];
						maxPosition[1] = currQueuePos[0][1];
						maxScore = currScoreTime[0];
						penalty = newPenalty;
					}
				}
			} // else
			// System.out.println("NOTIME");
		}
		
		// make sure it's destroyable/empty
		if (newDestroyable[newPosDir[0]][newPosDir[1]] == 0) {
			newScoreTime[0] = currScoreTime[0];
			newScoreTime[1] = currScoreTime[1];
			// destroy deducts score later also deducts time
			if ((tempPiece = 
						playingboard[newPosDir[0]][newPosDir[1]]) != ' ') {
				newScoreTime[0] -= 3;
				newScoreTime[1] += 1;
			}

			for(int a = 0; a < QUEUESIZE; a++)
				for(int b = 0; b < 2; b++)
					newQueue[a][b] = currQueuePos[a][b];

			for(int i  = 0; i < 5; i++) {
				if (currQueuePos[i][0] == -1) {
					if(getDir(newPosDir[2], queue[i]) != NODIR) {
						newQueue[i][0] = newPosDir[0];
						newQueue[i][1] = newPosDir[1];

						touched[newPosDir[0]][newPosDir[1]]++;
						
						newBoard[newPosDir[0]][newPosDir[1]] = queue[i];

						// doFlow(playingboard, newDestroyable, newPosDir, 1);

						doSearch(newBoard, newDestroyable, 
								newQueue, newPosDir, newScoreTime);
						newBoard[newPosDir[0]][newPosDir[1]] = tempPiece;

						// reset queue
						newQueue[i][0] = -1;
						newQueue[i][1] = -1;
					}
				}
			}
		}

		if (playingboard[newPosDir[0]][newPosDir[1]] != ' ') {
			newScoreTime = doFlow(playingboard, newDestroyable, 
					newPosDir, 1);
			newScoreTime[0] += currScoreTime[0];
			newScoreTime[1] = currScoreTime[1];

			if (currPosDir[0] != newPosDir[0] || 
				currPosDir[1] != newPosDir[1])
				doSearch(newBoard, newDestroyable, currQueuePos, 
						newPosDir, newScoreTime);
		}
	}

	/**
	 * This method restricts the game to put certain pieces 
	 * at places that will lead to dead ends
	 * @param currQueuePos records the position of the queue pieces for each queue piece
	 */ 
	private boolean placeConstraints(final char playingboard[][], final byte currQueuePos[][])
	{
		/*
		 * TODO
		 * Place constraints against grid borders and constraints along positions 
		 * that the piece will lead the path to a dead end with another existing component
		 * Possible bug : currScore is not adjusted but logic forces the game to a NOCHOICE state
		 */
		 
		int x = currQueuePos[0][0];
		int y = currQueuePos[0][1];
		
		if(queue[0]=='|' && 
		  ((y==6 || y==0) || 
			   	 ( playingboard[x][y+1]=='c' ||
			   	   playingboard[x][y+1]=='z' ||
			   	   playingboard[x][y+1]=='-' ||	 
			   	   playingboard[x][y-1]=='e' ||
			   	   playingboard[x][y-1]=='q' ||
			   	   playingboard[x][y-1]=='-' ) ) )
		{
			maxPosition[0] =-1;
			return true;
		}		
		else if(queue[0]=='-' && 
			   ( (x==6 || x==0) || 
			   	 ( playingboard[x+1][y]=='c' ||
			   	   playingboard[x+1][y]=='|' ||	 
			   	   playingboard[x+1][y]=='e' ||
			   	   playingboard[x-1][y]=='z' ||	
			   	   playingboard[x-1][y]=='|' || 
			   	   playingboard[x-1][y]=='q') ) )
		{
			maxPosition[0] =-1;
			return true;
		}
		else if(queue[0]=='z' && 
			   ((x==0 || y==6)|| 
			   	 ( playingboard[x][y+1]=='c' ||
			   	   playingboard[x][y+1]=='z' ||	 
			   	   playingboard[x][y+1]=='-' ||
			   	   playingboard[x-1][y]=='z' ||
			   	   playingboard[x-1][y]=='q' ||	 
			   	   playingboard[x-1][y]=='|') ) )
		{
			maxPosition[0] =-1;
			return true;
		}
		else if(queue[0]=='c' && 
			   ((x==6 || y==6) || 
			   	 ( playingboard[x][y+1]=='c' ||
			   	   playingboard[x][y+1]=='-' ||	 
			   	   playingboard[x][y+1]=='z' ||
			   	   playingboard[x+1][y]=='c' ||
			   	   playingboard[x+1][y]=='|' ||	 
			   	   playingboard[x+1][y]=='e') ) )
		{
			maxPosition[0] =-1;
			return true;
		}
		else if(queue[0]=='q' && 
			   ((x==0 || y==0)|| 
			   	 ( playingboard[x][y-1]=='e' ||
			   	   playingboard[x][y-1]=='q' ||	 
			   	   playingboard[x][y-1]=='-' ||
			   	   playingboard[x-1][y]=='z' ||
			   	   playingboard[x-1][y]=='q' ||	 
			   	   playingboard[x-1][y]=='|') ) )
		{
			maxPosition[0] =-1;
			return true;
		}
		else if(queue[0]=='e' && 
			   ((x==6 || y==0) || 
			   	 ( playingboard[x][y-1]=='e' ||
			   	   playingboard[x][y-1]=='q' ||	 
			   	   playingboard[x][y-1]=='-' ||
			   	   playingboard[x+1][y]=='c' ||
			   	   playingboard[x+1][y]=='|' ||	 
			   	   playingboard[x+1][y]=='e') ) )
		{
			maxPosition[0] =-1;
			return true;
		}
		else if(queue[0]=='+' && 
			    (x==6 || x==0 || y==6 || y==0))
		{
			/*
			 *For the cross piece, it will be allowed to be placed on the borders if and only if
			 *connecting pieces are already on the playing board. Else they should be placed within 
			 *a 6 X 6 gridbox that has a 1 box perimeter from the actual grid sides.
			 */
			 
			if( (x==6 || x==0) && !(y==6 || y==0) )
			{
				if( playingboard[ x ][ y-1 ] != 'c' ||
			        playingboard[ x ][ y-1 ] != 'z' ||
			        playingboard[ x ][ y-1 ] != '-' ||
			        playingboard[ x ][ y+1 ] != 'e' ||
			        playingboard[ x ][ y+1 ] != 'q' ||
			        playingboard[ x ][ y+1 ] != '-' ) 
			      		return false;
			}
			else if( (y==6 || y==0) && !(x==6 || x==0) )
			{	
			    if( playingboard[ x-1 ][ y ] != 'z' || 
			        playingboard[ x-1 ][ y ] != 'q' ||
			        playingboard[ x-1 ][ y ] != '|' || 
			        playingboard[ x+1 ][ y ] != 'c' ||	
			        playingboard[ x+1 ][ y ] != 'e' ||
			        playingboard[ x+1 ][ y ] != '|' )
			    		return false;
			}
			
			maxPosition[0] =-1;
			return true;
		}
		
		return false;	
			
	}
	
	/**
	 * Simulates a flow by starting from a given position
	 * This method traverses the current starting position with the direction given
	 * It DOES NOT ASSUME that the current starting position has been traversed
	 * The direction given is the direction BEFORE reaching this position
	 *
	 * @param playingboard a playing board with tiles to traverse
	 * @param destroyable an array of bytes to indicate whether tiles have any flow
	 * @param checkPosDir the current position given with the direction
	 * @param advance the number of steps to advance
	 * @return the score after traversing through the thing 
	 *         and the time taken to traverse
	 */
	private int[] doFlow (final char playingboard[][], 
			byte destroyable[][], byte checkPosDir[]) {
		return doFlow(playingboard, destroyable, checkPosDir, INF);
	}
	private int[] doFlow (final char playingboard[][], 
			byte destroyable[][], byte checkPosDir[], int advance) {

		byte x = checkPosDir[0], y = checkPosDir[1], dir = checkPosDir[2];
		// TODO check if NEW IS NEEDED
		int scoreTime[] = {0, 0};

		// if there is a direction to move
		while ((dir = getDir(dir, playingboard[x][y])) != NODIR && advance-- > 0)
		{
			// move
			if (destroyable[x][y] >= 1 && playingboard[x][y] != '+' 
					&& playingboard[x][y] != '\'') {
				break;
			} else if (destroyable[x][y] == 2 && playingboard[x][y] == '+') {
				break;
			}
			
			destroyable[x][y] += 1;
			scoreTime[0] += 2;
			scoreTime[1] += 3;

			// bonus
			if (destroyable[x][y] == 2 && playingboard[x][y] == '+')
				scoreTime[0] += 5;

			switch(dir) {
				case WEST:
					x -= 1;
					break;
				case NORTH:
					y -= 1;
					break;
				case EAST:
					x += 1;
					break;
				case SOUTH:
					y += 1;
					break;
			}

			// check if landed to a valid position
			if (x<0 || x >= MAXX || y<0 || y >= MAXY)
			{
				if (destroyable[checkPosDir[0]][checkPosDir[1]] == 2 && 
					playingboard[checkPosDir[0]][checkPosDir[1]] == '+')
					scoreTime[0] -= 5;

				// backflow when you reach the wall
				if (realDestroyable[checkPosDir[0]][checkPosDir[1]] == 0 
					&& destroyable[checkPosDir[0]][checkPosDir[1]] >= 1) {
					destroyable[checkPosDir[0]][checkPosDir[1]] -= 1;
				}

				scoreTime[0] -= 2;
				scoreTime[1] -= 3;

				break;
			} else {

				checkPosDir[0] = x;
				checkPosDir[1] = y;
				checkPosDir[2] = dir;
			}
		}

		return scoreTime;
	}


	private int checkSides(int x, int y, char piece)
	{
		int score=0;
		switch (piece)
		{
			case '|':
				//don't put any | pieces at the top and bottom borders
				if (y == 6 || y == 0)
					score=-INF;
				if (x == 0)
					score += 1;
				if (x == 6)//if(x == 1)?? question to chris, why x==1?
					score += 1;
				if (y + 1 < MAXY)
				{
					if (realBoard[x][y + 1] == ' ')
						score += 2;
					else if (getDir(SOUTH, realBoard[x][y + 1]) != NODIR)
						score += 3;
				}
				if (y - 1 >= 0)
				{
					if (realBoard[x][y - 1] == ' ')
						score += 2;
					else if (getDir(NORTH, realBoard[x][y - 1]) != NODIR)
						score += 3;
				}
				if (x + 1 < MAXX)
				{
					if (getDir(EAST, realBoard[x + 1][y]) == NODIR)
						score -= 2;
					if (realBoard[x + 1][y] != ' ')
						score += 1;
				}
				if (x - 1 >= 0)
				{
					if (getDir(WEST, realBoard[x - 1][y]) == NODIR)
						score += 2;
					if (realBoard[x - 1][y] != ' ')
						score += 1;
				}
				break;
			case '-':
				//don't put any - pieces at the left and right borders
				if (x == 6 || x == 0)
					score=-INF;
				if (y == 0)
					score += 1;
				if (y == 6)
					score += 1;
				if (x + 1 < MAXX)
				{
					if (realBoard[x + 1][y] == ' ')
						score += 2;
					else if (getDir(EAST, realBoard[x + 1][y]) != NODIR)
						score += 3;
				}
				if (x - 1 >= 0)
				{
					if (realBoard[x - 1][y] == ' ')
						score += 2;
					else if (getDir(WEST, realBoard[x - 1][y]) != NODIR)
						score += 3;
				}
				if (y + 1 < MAXY)
				{
					if (getDir(SOUTH, realBoard[x][y + 1]) == NODIR)
						score += 2;
					if (realBoard[x][y + 1] != ' ')
						score += 1;
				}
				if (y - 1 >= 0)
				{
					if (getDir(NORTH, realBoard[x][y - 1]) == NODIR)
						score -= 2;
					if (realBoard[x][y - 1] != ' ')
						score += 1;
				}
				break;
			case 'c':
				if (x == 0)
					score += 2;
				if (y == 0)
					score += 2;
				if (y + 1 < MAXY)
				{
					if (realBoard[x][y + 1] == ' ')
						score += 2;
					else if (getDir(SOUTH, realBoard[x][y + 1]) != NODIR)
						score += 4;
				}
				if (x + 1 < MAXX)
				{
					if (realBoard[x + 1][y] == ' ')
						score += 2;
					else if (getDir(EAST, realBoard[x + 1][y]) != NODIR)
						score += 4;
				}
				if (y - 1 >= 0)
				{
					if (getDir(NORTH, realBoard[x][y - 1]) == NODIR)
						score += 2;
					if (realBoard[x][y - 1] != ' ')
						score += 1;
				}
				if (x - 1 >= 0)
				{
					if (getDir(WEST, realBoard[x - 1][y]) == NODIR)
						score -= 2;
					if (realBoard[x - 1][y] != ' ')
						score += 1;
				}
				break;
			case 'z':
				if (x == 6)
					score += 2;
				if (y == 0)
					score += 2;
				if (x - 1 >= 0)
				{
					if (realBoard[x - 1][y] == ' ')
						score += 2;
					else if (getDir(WEST, realBoard[x - 1][y]) != NODIR)
						score += 3;
				}
				if (y + 1 < MAXY)
				{
					if (realBoard[x][y + 1] == ' ')
						score += 2;
					else if (getDir(SOUTH, realBoard[x][y + 1]) != NODIR)
						score += 3;
				}
				if (y - 1 >= 0)
				{
					if (getDir(NORTH, realBoard[x][y - 1]) == NODIR)
						score += 2;
					if (realBoard[x][y - 1] != ' ')
						score += 1;
				}
				if (x + 1 < MAXY)
				{
					if (getDir(EAST, realBoard[x + 1][y]) == NODIR)
						score += 2;
					if (realBoard[x + 1][y] != ' ')
						score += 1;
				}
				break;
			case 'e':
				if (x == 0)
					score += 2;
				if (y == 6)
					score += 2;
				if (y - 1 >= 0)
				{
					if (realBoard[x][y - 1] == ' ')
						score += 2;
					else if (getDir(NORTH, realBoard[x][y - 1]) != NODIR)
						score += 3;
				}
				if (x + 1 < MAXX)
				{
					if (realBoard[x + 1][y] == ' ')
						score += 2;
					else if (getDir(EAST, realBoard[x + 1][y]) != NODIR)
						score += 3;
				}
				if (x - 1 >= 0)
				{
					if (getDir(WEST, realBoard[x - 1][y]) == NODIR)
						score += 2;
					if (realBoard[x - 1][y] != ' ')
						score += 1;
				}
				if (y + 1 < MAXY)
				{
					if (getDir(SOUTH, realBoard[x][y + 1]) == NODIR)
						score += 2;
					if (realBoard[x][y + 1] != ' ')
						score += 1;
				}
				break;
			case 'q':
				if (x == 6)
					score += 2;
				if (y == 6)
					score += 2;
				if (x - 1 >= 0)
				{
					if (getDir(WEST, realBoard[x - 1][y]) != NODIR)
						score += 3;
					if (realBoard[x - 1][y] == ' ')
						score += 2;
				}
				if (y - 1 >= 0)
				{
					if (getDir(NORTH, realBoard[x][y - 1]) != NODIR)
						score += 3;
					if (realBoard[x][y - 1] == ' ')
						score += 2;
				}
				if (y + 1 < MAXY)
				{
					if (getDir(SOUTH, realBoard[x][y + 1]) == NODIR)
						score += 2;
					if (realBoard[x][y + 1] != ' ')
						score += 1;
				}
				if (x + 1 < MAXX)
				{
					if (getDir(EAST, realBoard[x + 1][y]) == NODIR)
						score += 2;
					if (realBoard[x + 1][y] != ' ')
						score += 1;
				}
				break;
			case '+':
				if (x + 1 < MAXX)
				{
					if (getDir(EAST, realBoard[x + 1][y]) != NODIR)
						score += 2;
					if (realBoard[x + 1][y] == ' ')
						score += 1;
				}
				if (x - 1 >= 0)
				{
					if (getDir(WEST, realBoard[x - 1][y]) != NODIR)
						score += 2;
					if (realBoard[x - 1][y] == ' ')
						score += 1;
				}
				if (y + 1 < MAXY)
				{
					if (getDir(SOUTH, realBoard[x][y + 1]) != NODIR)
						score += 2;
					if (realBoard[x][y + 1] == ' ')
						score += 1;
				}
				if (y - 1 >= 0)
				{
					if (getDir(NORTH, realBoard[x][y - 1]) != NODIR)
						score += 2;
					if (realBoard[x][y - 1] == ' ')
						score += 1;
				}
				if (x == 0 || x == 6)
					score -= 2;
				if (y == 0 || y == 6)
					score -= 2;
				break;
			// blank piece or no direction
			default:
				score += 0;
		}

		// just to weigh the things
		// Put it as far from the realOozeSpot as possible
		score *= 2;
		score += Math.abs(x - realOozeSpot[0]);
		score += Math.abs(y - realOozeSpot[1]);

		return score;
	}
}
